home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / program / qlib205.zip / QLIB.ZIP / SRC / QLIB / SPAWN.ASM < prev    next >
Assembly Source File  |  1997-07-08  |  13KB  |  696 lines

  1. ;todo : make sure there is no '*' or '?' in the path or filename
  2. ;     : this is not really necessary cause the 4b00h call will fail anyways
  3.  
  4. ;BUG! overlay simply calls program and then quits if successful
  5.  
  6. ;FIX! : v2.02 : enviroment lookup was fixed
  7.  
  8. include qlib.inc
  9. include process.inc
  10. include string.inc
  11. include dos.inc
  12. include stdlib.inc
  13. include alloc.inc
  14. include errno.inc
  15. include stdio.inc
  16.  
  17. ;Spawn and all it's variants were hard to implement.
  18. ;Everything is supported.  
  19.  
  20. .data?
  21.   dopath db ?  ;flag - search fn for program
  22.   doenv db ?   ;flag - made new enviroment
  23.   dot db ?     ;flag - a . is in fn
  24.   bat db ?     ;flag - filename is a BAT file
  25.  
  26.   fn dd ?      ;filename to exec
  27.   fnl dd ?     ;length of filename
  28.   mode dw ?    ;from func  (P_WAIT=0 P_NOWAIT=1[error]  P_OVERLAY=2)
  29.   arglen db ?               ;parameters len
  30.   args db 128 dup (?)       ;parameters (arguments)
  31.   ff ffblk <>
  32.   path dd ?                 ;pts to %PATH% in the enviroment
  33.   thepath db 128 dup (?)    ;a part of %PATH%
  34.   totalpath db 128 dup (?)  ;path and filename
  35.   tfnl dd ?                 ;total file name length
  36.   envirohand dd ?           ;handle for enviro memory block (32k)
  37.  
  38. .data
  39.   pbs struct                ;parameter block
  40.     enviroff dd ?
  41.     envirsel dw ?
  42.     cto dd offset arglen    ;command tail
  43.     cts dw ?
  44.     fcb1 dd 0
  45.     fcb2 dd 0
  46.   pbs ends
  47.   pb pbs <>
  48.  
  49. .code
  50. findit proc private,p:dword,at:byte
  51.   local len:dword
  52.   ;looks for program "p+fn"
  53.   ;if at==\\ then a \\ is not added between 'p' and 'fn'
  54.   ;at is simply the last char of 'p'
  55.   callp strlen,p
  56.   mov ebx,eax
  57.   add ebx,fnl
  58.   mov len,ebx
  59.   .if ebx>127
  60.     mov eax,ERROR
  61.     ret
  62.   .endif
  63.   mov ebx,offset totalpath
  64.   callp strcpy,ebx,p
  65.   .if at!='\'
  66.     callp strcat,ebx,"\\"
  67.     inc len
  68.   .endif
  69.   callp strcat,ebx,fn
  70.   callp findfirst,ebx,0h,offset ff
  71.  
  72.   .if !eax
  73.     ret     ;found it!
  74.   .endif
  75. ;try and add .COM and .EXE (order is important to follow DOS implementation)
  76.   .if len>(127-5)
  77.     mov eax,ERROR
  78.     ret           ;not enough room to add it
  79.   .endif
  80.   .if dot
  81.     mov eax,ERROR
  82.   .endif
  83.     
  84. tryit:  ;there is no . so we can add .COM and then .EXE
  85.   mov esi,offset totalpath
  86.   add esi,len
  87.   mov len,esi  ;save for ...
  88.   callp strcpy,esi,".COM"
  89.   callp findfirst,offset totalpath,0h,offset ff
  90.   .if !eax
  91.     ret
  92.   .endif       
  93.   mov esi,len  ;... here
  94.   callp strcpy,esi,".EXE"
  95.   callp findfirst,offset totalpath,0h,offset ff
  96.   ;EAX is returned here
  97.   ret
  98. findit endp
  99.  
  100. add_bat proc private
  101.   ;adds "/C totalpath " in front of all ARGS (if possible)
  102.   ;changes totalpath to %COMSPEC%
  103.  
  104.   callp strlen,offset totalpath
  105.   mov tfnl,eax
  106.   add eax,4
  107.   xor ebx,ebx
  108.   mov bl,arglen
  109.   .if ebx>eax
  110.     mov eax,ERROR
  111.     ret
  112.   .endif
  113.  
  114.   sub esp,128  ;reserve space for temp storage
  115.  
  116.   mov ebx,esp
  117.   callp memcpy,ebx,offset args,arglen
  118.   callp memcpy,offset args," /C ",4
  119.   callp memcpy,offset args+4,offset totalpath,tfnl
  120.   mov eax,esp
  121.   mov ebx,offset args+4
  122.   add ebx,tfnl
  123.   callp memcpy,ebx,eax,arglen
  124.  
  125.   callp getenv,"COMSPEC"
  126.   .if eax==NULL
  127.     mov eax,ERROR
  128.     add esp,128
  129.     ret
  130.   .endif
  131.   callp strcpy,offset totalpath,eax
  132.  
  133.   mov eax,tfnl
  134.   add eax,4
  135.   add arglen,al
  136.  
  137.   xor eax,eax
  138.   add esp,128
  139.   ret
  140. add_bat endp
  141.  
  142. _spawn proc private
  143.   pushad
  144.   .if mode == P_NOWAIT
  145.     mov errno,EINVAL
  146.     jmp bad
  147.   .endif
  148.  
  149. ;misc setup
  150.   callp strlen,fn
  151.   .if eax>127
  152.     mov errno,ENOENT   ;path not found
  153.     jmp bad
  154.   .endif
  155.   mov fnl,eax
  156.  
  157.   mov edi,fn
  158.   mov ecx,eax
  159.   mov al,'.'
  160.   repnz scasb
  161.   .if zero?  ;a . was found
  162.     mov dot,1
  163.   .else
  164.     mov dot,0
  165.   .endif
  166.   callp memicmp,edi,"BAT",3
  167.   .if !eax
  168.     mov bat,1
  169.   .else
  170.     mov bat,0
  171.   .endif
  172.  
  173.   .if !doenv
  174.     ;use parent's enviro for child process
  175.     mov eax,_environ
  176.     mov pb.enviroff,eax
  177.   .endif
  178.   mov ax,seldata
  179.   mov pb.envirsel,ax
  180.   mov pb.cts,ax
  181.  
  182. ;find child
  183.   callp findit,"",'\'   ;make at='\' so that it will not add a '\'
  184.   .if !eax
  185.     jmp doit
  186.   .endif
  187.   mov ecx,fn
  188.   .if !dopath
  189.     mov errno,ENOENT
  190.     jmp bad
  191.   .endif
  192.  
  193. ;search for '\' or ':'  (if any are found then we cannot cruz thru %path%)
  194.   mov edi,fn
  195.   mov ecx,fnl
  196.   mov al,'\'
  197.   repnz scasb
  198.   .if zero?
  199.     mov errno,ENOENT
  200.     jmp bad
  201.   .endif
  202.   mov edi,fn
  203.   mov ecx,fnl
  204.   mov al,':'
  205.   repnz scasb
  206.   .if zero?
  207.     mov errno,ENOENT
  208.     jmp bad
  209.   .endif
  210.  
  211.   callp getenv,"PATH"
  212.   .if eax==NULL
  213.     mov errno,ENOENT
  214.     jmp bad
  215.   .endif
  216.   mov path,eax
  217. tryagain:
  218.   mov esi,path
  219.   mov edi,offset thepath
  220.   mov cl,1
  221. @@:
  222.   lodsb
  223.   .if ((al==';') || (al==0))
  224.     .if !al
  225.       mov cl,0  ;Stop after this attempt
  226.     .endif
  227.     mov al,0
  228.     stosb
  229.     mov path,esi  ;save new pos
  230.     jmp tryit
  231.   .endif
  232.   mov bl,al
  233.   stosb
  234.   .if edi>offset thepath+120    ;path too long
  235. @@1:
  236.     lodsb
  237.     .if al==';'
  238.       mov path,esi
  239.       jmp tryagain
  240.     .endif
  241.     .if !al
  242.       mov errno,ENOENT
  243.       jmp bad
  244.     .endif
  245.     jmp @@1
  246.   .endif
  247.   jmp @b
  248.  
  249. tryit:
  250.   push ebx
  251.   push ecx
  252.   callp findit,offset thepath,bl  ;does not preserve regs
  253.   pop ecx
  254.   pop ebx
  255.   .if eax==ERROR
  256.     .if !cl
  257.       mov errno,ENOENT
  258.       jmp bad
  259.     .endif
  260.     jmp tryagain
  261.   .endif
  262. doit:
  263.   ;SPAWN! (or exec)  
  264.   .if bat
  265.     call add_bat
  266.     .if eax==ERROR
  267.       mov eax,ENOENT
  268.       jmp bad
  269.     .endif
  270.   .endif
  271.   .if mode==P_OVERLAY
  272.     ;OK, exec is very tricky.
  273.     ;PSP+ah is the terminate vector.  which must be changed to something
  274.     ;that will load something and then go back to COMMAND.COM (or whatever)
  275.     ;when we terminate (4ch)
  276.     ;But what memory do we alloc (if we go thru DOS it will be unalloc as
  277.     ;soon as we end program).  We need enough RAM to have a little code and the
  278.     ;parameter block.  Any ideas?
  279.  
  280.     ;for now I will simply evec new program and then quit if successful
  281.     mov ax,4b00h    ;load & exec program
  282.     mov edx,offset totalpath
  283.     mov ebx,offset pb
  284.     int 21h
  285.     .if carry?
  286.       mov errno,ax
  287.       jmp bad
  288.     .endif
  289.     callp exit,0   ;exit if successful
  290.   .else
  291.     mov ax,4b00h    ;load & exec program
  292.     mov edx,offset totalpath
  293.     mov ebx,offset pb
  294.     int 21h
  295.     .if carry?
  296.       mov errno,ax
  297.       jmp bad
  298.     .endif
  299.     mov ah,4dh   ;get error code of child
  300.     int 21h
  301.     xor ebx,ebx
  302.     mov bl,al
  303.     mov [esp+7*4],ebx  ;save as EAX
  304.   .endif
  305.   mov eax,envirohand
  306.   .if eax
  307.     callp free,eax
  308.   .endif
  309.   mov edx,_dta
  310.   mov ah,1ah
  311.   int 21h  ;reset DTA
  312.   popad
  313.   xor eax,eax
  314.   ret
  315. bad:
  316.   mov edx,_dta
  317.   mov ah,1ah
  318.   int 21h  ;reset DTA
  319.   mov eax,envirohand
  320.   .if eax
  321.     callp free,eax
  322.   .endif
  323.   popad
  324.   mov eax,ERROR
  325.   ret
  326. _spawn endp
  327.  
  328. setarg proc private,va:dword  ;ret:eax=pt to next arg after NULL
  329.   local len:dword
  330.   pushad
  331.   mov ebx,va
  332. ;  mov ecx,128/4           ;clear ARG area (not needed)
  333. ;  mov edi,offset args
  334. ;  xor eax,eax
  335. ;  rep stosd
  336.   mov edx,[ebx]
  337.   mov ecx,offset args
  338.   mov bptr[ecx],' ' ;must insert a leading space
  339.   inc ecx
  340.   .while edx
  341.     callp strlen,edx
  342.     mov len,eax
  343.     add eax,ecx
  344.     .if eax>(126+offset args)  ;need a space after para too
  345.       popad
  346.       mov eax,ERROR
  347.       mov errno,E2BIG
  348.       ret
  349.     .endif
  350.     callp strcpy,ecx,edx
  351.     add ecx,len
  352.     mov bptr[ecx],' '
  353.     inc ecx
  354.     add ebx,4
  355.     mov edx,[ebx]
  356.   .endw
  357.   add ebx,4  ;pt to next after NULL (in case the enviro array is after it)
  358.   mov bptr[ecx],0
  359.   sub ecx,offset args
  360.   mov arglen,cl
  361.   mov [esp+7*4],ebx  ;save as EAX
  362.   popad
  363.   ret
  364. setarg endp
  365.  
  366. setenv proc private,e:dword
  367.   local len:dword
  368.   local max:dword
  369.   ;setup an enviro block
  370.   callp malloc,32*1024  ;MAX size of enviro block
  371.   .if eax==NULL
  372.     mov errno,ENOMEM
  373.     mov eax,ERROR
  374.     ret
  375.   .endif
  376.   mov pb.enviroff,eax
  377.   mov envirohand,eax
  378.   pushad
  379.   mov ebx,e
  380.   mov edx,[ebx]
  381.   mov ecx,eax
  382.   mov max,ecx
  383.   add max,32*1024
  384.   .while edx
  385.     callp strlen,edx
  386.     mov len,eax
  387.     add eax,ecx
  388.     add eax,2     ;FIX! v2.02 : we need room for the zero and double zero
  389.     cmp eax,max
  390.     ja full
  391.     callp strcpy,ecx,edx
  392.     add ecx,len
  393.     inc ecx  ;skip over 0
  394.     add ebx,4
  395.     mov edx,[ebx]
  396.   .endw
  397. full:
  398.   mov bptr[ecx],0 ;put last 0 (this is the double 0 thingy)
  399.   popad
  400.   xor eax,eax
  401.   ret
  402. setenv endp
  403.  
  404. ;list of args passed
  405. spawnl proc,m:word,tp:dword,va:vararg ;...,NULL
  406.   mov eax,tp
  407.   mov fn,eax
  408.   mov ax,m
  409.   mov mode,ax
  410.   lea eax,va
  411.   callp setarg,eax
  412.   .if eax==ERROR
  413.     ret
  414.   .endif
  415.   mov doenv,0  ;use parent's enviroment
  416.   mov dopath,0
  417.   mov envirohand,0
  418.   call _spawn
  419.   ret
  420. spawnl endp
  421.  
  422. spawnle proc,m:word,tp:dword,va:vararg ;...,NULL,char *envp[]
  423.   mov eax,tp
  424.   mov fn,eax
  425.   mov ax,m
  426.   mov mode,ax
  427.   lea eax,va
  428.   callp setarg,eax
  429.   .if eax==ERROR
  430.     ret
  431.   .endif
  432.   mov eax,[eax]    ;get env
  433.   callp setenv,eax
  434.   .if eax==ERROR
  435.     ret
  436.   .endif
  437.   mov doenv,1  ;use new enviroment
  438.   mov dopath,0
  439.   call _spawn
  440.   ret
  441. spawnle endp
  442.  
  443. spawnlp proc,m:word,tp:dword,va:vararg ;...,NULL
  444.   mov eax,tp
  445.   mov fn,eax
  446.   mov ax,m
  447.   mov mode,ax
  448.   lea eax,va
  449.   callp setarg,eax
  450.   .if eax==ERROR
  451.     ret
  452.   .endif
  453.   mov doenv,0  ;use parent's enviroment
  454.   mov dopath,1
  455.   mov envirohand,0
  456.   call _spawn
  457.   ret
  458. spawnlp endp
  459.  
  460. spawnlpe proc,m:word,tp:dword,va:vararg ;...,NULL,char *envp[]
  461.   mov eax,tp
  462.   mov fn,eax
  463.   mov ax,m
  464.   mov mode,ax
  465.   lea eax,va
  466.   callp setarg,eax
  467.   .if eax==ERROR
  468.     ret
  469.   .endif
  470.   mov eax,[eax]    ;get env
  471.   callp setenv,eax
  472.   .if eax==ERROR
  473.     ret
  474.   .endif
  475.   mov doenv,1  ;new enviroment
  476.   mov dopath,1
  477.   call _spawn
  478.   ret
  479. spawnlpe endp
  480.  
  481. ; V variants follow
  482.  
  483. spawnv proc,m:word,tp:dword,va:dword
  484.   mov eax,tp
  485.   mov fn,eax
  486.   mov ax,m
  487.   mov mode,ax
  488.   callp setarg,va
  489.   .if eax==ERROR
  490.     ret
  491.   .endif
  492.   mov doenv,0  ;use parent's enviroment
  493.   mov dopath,0
  494.   mov envirohand,0
  495.   call _spawn
  496.   ret
  497. spawnv endp
  498.  
  499. spawnve proc,m:word,tp:dword,va:dword,e:dword
  500.   mov eax,tp
  501.   mov fn,eax
  502.   mov ax,m
  503.   mov mode,ax
  504.   callp setarg,va
  505.   .if eax==ERROR
  506.     ret
  507.   .endif
  508.   callp setenv,e
  509.   .if eax==ERROR
  510.     ret
  511.   .endif
  512.   mov doenv,1  ;use parent's enviroment
  513.   mov dopath,0
  514.   call _spawn
  515.   ret
  516. spawnve endp
  517.  
  518. spawnvp proc,m:word,tp:dword,va:dword
  519.   mov eax,tp
  520.   mov fn,eax
  521.   mov ax,m
  522.   mov mode,ax
  523.   callp setarg,va
  524.   .if eax==ERROR
  525.     ret
  526.   .endif
  527.   mov doenv,0  ;use parent's enviroment
  528.   mov dopath,1
  529.   mov envirohand,0
  530.   call _spawn
  531.   ret
  532. spawnvp endp
  533.  
  534. spawnvpe proc,m:word,tp:dword,va:dword,e:dword
  535.   mov eax,tp
  536.   mov fn,eax
  537.   mov ax,m
  538.   mov mode,ax
  539.   callp setarg,va
  540.   .if eax==ERROR
  541.     ret
  542.   .endif
  543.   callp setenv,e
  544.   .if eax==ERROR
  545.     ret
  546.   .endif
  547.   mov doenv,1  ;use parent's enviroment
  548.   mov dopath,1
  549.   call _spawn
  550.   ret
  551. spawnvpe endp
  552.  
  553. ;list of args passed
  554. execl proc,tp:dword,va:vararg ;...,NULL
  555.   mov eax,tp
  556.   mov fn,eax
  557.   lea eax,va
  558.   callp setarg,eax
  559.   .if eax==ERROR
  560.     ret
  561.   .endif
  562.   mov doenv,0  ;use parent's enviroment
  563.   mov dopath,0
  564.   mov mode,P_OVERLAY
  565.   mov envirohand,0
  566.   call _spawn
  567.   ret
  568. execl endp
  569.  
  570. execle proc,tp:dword,va:vararg ;...,NULL,char *envp[]
  571.   mov eax,tp
  572.   mov fn,eax
  573.   lea eax,va
  574.   callp setarg,eax
  575.   .if eax==ERROR
  576.     ret
  577.   .endif
  578.   mov eax,[eax]    ;get env
  579.   callp setenv,eax
  580.   .if eax==ERROR
  581.     ret
  582.   .endif
  583.   mov doenv,1  ;use new enviroment
  584.   mov dopath,0
  585.   mov mode,P_OVERLAY
  586.   call _spawn
  587.   ret
  588. execle endp
  589.  
  590. execlp proc,tp:dword,va:vararg ;...,NULL
  591.   mov eax,tp
  592.   mov fn,eax
  593.   lea eax,va
  594.   callp setarg,eax
  595.   .if eax==ERROR
  596.     ret
  597.   .endif
  598.   mov doenv,0  ;use parent's enviroment
  599.   mov dopath,1
  600.   mov mode,P_OVERLAY
  601.   mov envirohand,0
  602.   call _spawn
  603.   ret
  604. execlp endp
  605.  
  606. execlpe proc,tp:dword,va:vararg ;...,NULL,char *envp[]
  607.   mov eax,tp
  608.   mov fn,eax
  609.   lea eax,va
  610.   callp setarg,eax
  611.   .if eax==ERROR
  612.     ret
  613.   .endif
  614.   mov eax,[eax]    ;get env
  615.   callp setenv,eax
  616.   .if eax==ERROR
  617.     ret
  618.   .endif
  619.   mov doenv,1  ;new enviroment
  620.   mov dopath,1
  621.   mov mode,P_OVERLAY
  622.   call _spawn
  623.   ret
  624. execlpe endp
  625.  
  626. ; V variants follow
  627.  
  628. execv proc,tp:dword,va:dword
  629.   mov eax,tp
  630.   mov fn,eax
  631.   callp setarg,va
  632.   .if eax==ERROR
  633.     ret
  634.   .endif
  635.   mov doenv,0  ;use parent's enviroment
  636.   mov dopath,0
  637.   mov mode,P_OVERLAY
  638.   mov envirohand,0
  639.   call _spawn
  640.   ret
  641. execv endp
  642.  
  643. execve proc,tp:dword,va:dword,e:dword
  644.   mov eax,tp
  645.   mov fn,eax
  646.   callp setarg,va
  647.   .if eax==ERROR
  648.     ret
  649.   .endif
  650.   callp setenv,e
  651.   .if eax==ERROR
  652.     ret
  653.   .endif
  654.   mov doenv,1  ;use parent's enviroment
  655.   mov dopath,0
  656.   mov mode,P_OVERLAY
  657.   call _spawn
  658.   ret
  659. execve endp
  660.  
  661. execvp proc,tp:dword,va:dword
  662.   mov eax,tp
  663.   mov fn,eax
  664.   callp setarg,va
  665.   .if eax==ERROR
  666.     ret
  667.   .endif
  668.   mov doenv,0  ;use parent's enviroment
  669.   mov dopath,1
  670.   mov mode,P_OVERLAY
  671.   mov envirohand,0
  672.   call _spawn
  673.   ret
  674. execvp endp
  675.  
  676. execvpe proc,tp:dword,va:dword,e:dword
  677.   mov eax,tp
  678.   mov fn,eax
  679.   callp setarg,va
  680.   .if eax==ERROR
  681.     ret
  682.   .endif
  683.   callp setenv,e
  684.   .if eax==ERROR
  685.     ret
  686.   .endif
  687.   mov doenv,1  ;use parent's enviroment
  688.   mov dopath,1
  689.   mov mode,P_OVERLAY
  690.   call _spawn
  691.   ret
  692. execvpe endp
  693.  
  694. end
  695.  
  696.